﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using log4net;
using System.IO;
using System.Reflection;

namespace PreCommitHook
{
    /// <summary>
    /// this class checks the policy configured in CommittedFilesPolicy.xml and determines if the committed file
    /// meets the given requirments.
    /// </summary>
    public class ContentPolicyManager
    {
        private static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// determines if the committed content is allowed according settings in CommittedFilesPolicy.xml
        /// </summary>
        /// <param name="name">name of the committed object (file or folder)</param>
        /// <param name="isFile">true if the content is file, false if the content is folder</param>
        /// <returns>false if the folder or file doesn't follow the policy configured in CommittedFilesPolicy.xml</returns>
        public static bool AllowContentCommit(string name, bool isFile)
        {
            if (isFile)
            {
                log.Info("AllowContentCommit called for a file " + name);                
                string extenstion = name.Substring(name.LastIndexOf(".") + 1);
                return !IsFileExtensionForbidden(extenstion);
            }
            else
            {
                string folderName = name.Substring(name.LastIndexOf("/") + 1);
                return !IsFolderForbidden(folderName);
            }

        }

        /// <summary>
        /// checks if the committed assembly is assembly which contains unit tests
        /// </summary>
        /// <param name="assemblyName">assembly name (must include .dll extension in its name</param>
        /// <returns>false if the assmebly contains unit tests, true otherwise</returns>
        public static bool ShouldCheckAssembly(string assemblyName)
        {
            log.Info(String.Format("ShouldCheckAssembly->IsFileExtensionForbidden called for {0}", assemblyName));
            return !IsFileExtensionForbidden(assemblyName);
        }
        private static bool IsFileExtensionForbidden(string fileExtension)
        {
            try
            {
                string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                XDocument xDoc = XDocument.Load(path + @"\Config\CommittedFilesPolicy.xml");

                var query = (from files in xDoc.Root.Elements("Files")
                             from file in files.Elements()
                             where file.Value.Equals(fileExtension)
                             select file.Value);

                return (query.ToList().Count > 0);
            }
            catch (Exception ex)
            {
                log.Info("Exception on loading xml for a file extension" + fileExtension + "\nException details " + ex.Message);
                throw ex;
            }
        }

        private static bool IsFolderForbidden(string folderName)
        {
            string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            XDocument xDoc = XDocument.Load(path + @"\Config\CommittedFilesPolicy.xml");
            var query = (from folders in xDoc.Root.Elements("Folders")
                         from folder in folders.Elements()
                         where folder.Value.Equals(folderName)
                         select folder.Value);

            return (query.ToList().Count > 0);
        }
    }
}
